/*
 *    Copyright 2009-2021 the original author or authors.
 *
 *    Licensed under the Apache License, Version 2.0 (the "License");
 *    you may not use this file except in compliance with the License.
 *    You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 *    Unless required by applicable law or agreed to in writing, software
 *    distributed under the License is distributed on an "AS IS" BASIS,
 *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *    See the License for the specific language governing permissions and
 *    limitations under the License.
 */
package org.apache.ibatis.reflection;

import java.util.Collection;
import java.util.List;
import java.util.Map;

import org.apache.ibatis.reflection.factory.ObjectFactory;
import org.apache.ibatis.reflection.property.PropertyTokenizer;
import org.apache.ibatis.reflection.wrapper.BeanWrapper;
import org.apache.ibatis.reflection.wrapper.CollectionWrapper;
import org.apache.ibatis.reflection.wrapper.MapWrapper;
import org.apache.ibatis.reflection.wrapper.ObjectWrapper;
import org.apache.ibatis.reflection.wrapper.ObjectWrapperFactory;

/**
 * 元对象
 *
 * @author Clinton Begin
 */
public class MetaObject {

  /**
   * 源对象
   */
  private final Object originalObject;

  /**
   * 对象包装器
   */
  private final ObjectWrapper objectWrapper;

  /**
   * 对象工厂
   */
  private final ObjectFactory objectFactory;

  /**
   * 对象包装器工厂
   */
  private final ObjectWrapperFactory objectWrapperFactory;

  /**
   * 反射工厂
   */
  private final ReflectorFactory reflectorFactory;

  /**
   * 构造
   *
   * @param object               目标对象
   * @param objectFactory        对象工厂
   * @param objectWrapperFactory 对象包装器工厂
   * @param reflectorFactory     反射工厂
   * @author evan Date : 2021/10/11
   */
  private MetaObject(Object object, ObjectFactory objectFactory, ObjectWrapperFactory objectWrapperFactory, ReflectorFactory reflectorFactory) {
    this.originalObject = object;
    this.objectFactory = objectFactory;
    this.objectWrapperFactory = objectWrapperFactory;
    this.reflectorFactory = reflectorFactory;

    // 如果对象是对象包装器类型
    // 则转为该类型对象
    if (object instanceof ObjectWrapper) {
      this.objectWrapper = (ObjectWrapper) object;
    } else if (objectWrapperFactory.hasWrapperFor(object)) {

      // 通过该包装器包装
      // 默认工厂直接返回 false
      // 如果要走此条件, 需要自实现 objectWrapperFactory

      this.objectWrapper = objectWrapperFactory.getWrapperFor(this, object);
    } else if (object instanceof Map) {

      // map 类型, 返回 map 包装器

      this.objectWrapper = new MapWrapper(this, (Map) object);
    } else if (object instanceof Collection) {

      // 集合类型, 返回集合包装器

      this.objectWrapper = new CollectionWrapper(this, (Collection) object);
    } else {

      // 其它类型, 使用 BeanWrapper

      this.objectWrapper = new BeanWrapper(this, object);
    }
  }

  /**
   * 构造元对象的静态方法
   *
   * @author evan Date : 2021/10/11
   */
  public static MetaObject forObject(Object object, ObjectFactory objectFactory, ObjectWrapperFactory objectWrapperFactory, ReflectorFactory reflectorFactory) {

    // 目标对象为空
    // 返回默认的 空 元对象
    if (object == null) {
      return SystemMetaObject.NULL_META_OBJECT;
    } else {
      // 调用构造方法创建元对象
      return new MetaObject(object, objectFactory, objectWrapperFactory, reflectorFactory);
    }
  }

  public ObjectFactory getObjectFactory() {
    return objectFactory;
  }

  public ObjectWrapperFactory getObjectWrapperFactory() {
    return objectWrapperFactory;
  }

  public ReflectorFactory getReflectorFactory() {
    return reflectorFactory;
  }

  public Object getOriginalObject() {
    return originalObject;
  }

  /**
   * 根据属性名获取属性值
   *
   * @param propName            属性名
   * @param useCamelCaseMapping 是否使用驼峰命名
   * @return 属性值
   * @author evan Date : 2021/10/11
   */
  public String findProperty(String propName, boolean useCamelCaseMapping) {

    // 调用包装器的根据属性名获取属性值
    return objectWrapper.findProperty(propName, useCamelCaseMapping);
  }

  public String[] getGetterNames() {
    return objectWrapper.getGetterNames();
  }

  public String[] getSetterNames() {
    return objectWrapper.getSetterNames();
  }

  public Class<?> getSetterType(String name) {
    return objectWrapper.getSetterType(name);
  }

  public Class<?> getGetterType(String name) {
    return objectWrapper.getGetterType(name);
  }

  public boolean hasSetter(String name) {
    return objectWrapper.hasSetter(name);
  }

  public boolean hasGetter(String name) {
    return objectWrapper.hasGetter(name);
  }

  /**
   * 根据属性名获取对象
   *
   * @param name 属性名
   * @return 对应的值
   * @author evan Date : 2021/10/13
   */
  public Object getValue(String name) {

    // 对属性名进行分词
    PropertyTokenizer prop = new PropertyTokenizer(name);

    // 有子表达式
    if (prop.hasNext()) {

      // 获取 metaObject 对象

      MetaObject metaValue = metaObjectForProperty(prop.getIndexedName());
      if (metaValue == SystemMetaObject.NULL_META_OBJECT) {
        return null;
      } else {

        // 采用递归形式获取子表达式的值
        return metaValue.getValue(prop.getChildren());
      }
    } else {

      // 无子表达式获取值
      return objectWrapper.get(prop);
    }
  }

  /**
   * 设置指定属性的值
   *
   * @param name  属性名
   * @param value 需要设置值
   * @author evan Date : 2021/10/13
   */
  public void setValue(String name, Object value) {

    // 对属性进行分词
    PropertyTokenizer prop = new PropertyTokenizer(name);

    // 有子表达式
    if (prop.hasNext()) {

      // 获取属性的值对应的封装对象 metaObject
      // 如果属性的值为 null, metaObject 就是默认的空对象
      // 就需要创建属性对象 使用的方法就是: objectWrapper.instantiatePropertyValue
      MetaObject metaValue = metaObjectForProperty(prop.getIndexedName());
      if (metaValue == SystemMetaObject.NULL_META_OBJECT) {
        if (value == null) {
          // don't instantiate child path if value is null

          // 属性值为 null 就不用再给它的属性设置值了
          return;
        } else {

          // 因为先判断属性是存在子表达式的
          // 所以这里创建的属性值就是上级表达式属性的值, 并且将该属性值设置到了 object
          // 下面的 setValue 使用的就是子表达的属性的值
          metaValue = objectWrapper.instantiatePropertyValue(name, prop, objectFactory);
        }
      }

      // 采用递归方式设置属性的值
      metaValue.setValue(prop.getChildren(), value);
    } else {

      // 无子表达式设置值
      objectWrapper.set(prop, value);
    }
  }

  /**
   * 根据属性名创建 MetaObject
   *
   * @author evan Date : 2021/10/13
   */
  public MetaObject metaObjectForProperty(String name) {

    // 根据属性名获取值
    // 若属性值为空, 则直接返回 null
    Object value = getValue(name);

    // 将其封装为 metaObject 对象
    // 这里若 value 等于 null, metaObject 就是默认空对象
    return MetaObject.forObject(value, objectFactory, objectWrapperFactory, reflectorFactory);
  }

  public ObjectWrapper getObjectWrapper() {
    return objectWrapper;
  }

  public boolean isCollection() {
    return objectWrapper.isCollection();
  }

  public void add(Object element) {
    objectWrapper.add(element);
  }

  public <E> void addAll(List<E> list) {
    objectWrapper.addAll(list);
  }

}
